import hashlib
import secrets
from typing import Optional
from fastapi import Request, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession

from module_speech.dao.speech_client_dao import ClientUserDao
from module_speech.entity.do.speech_client_user_do import SpeechClientUserDO
from utils.log_util import logger


class SpeechAuthUtil:
    class RateLimiter:
        """
        简单的内存速率限制器
        """
        def __init__(self):
            self._requests = {}  # {user_id: [(timestamp, count), ...]}

        async def is_allowed(self, user_id: str, limit_per_minute: int) -> tuple[bool, dict]:
            import time
            current_time = time.time()
            current_minute = int(current_time // 60)
            # 清理过期记录
            if user_id in self._requests:
                self._requests[user_id] = [
                    (minute, count) for minute, count in self._requests[user_id]
                    if current_minute - minute < 1
                ]
            current_count = 0
            for minute, count in self._requests.get(user_id, []):
                if minute == current_minute:
                    current_count = count
                    break
            if current_count >= limit_per_minute:
                return False, {
                    'allowed': False,
                    'limit': limit_per_minute,
                    'current': current_count,
                    'reset_time': (current_minute + 1) * 60
                }
            if user_id not in self._requests:
                self._requests[user_id] = []
            updated = False
            for i, (minute, count) in enumerate(self._requests[user_id]):
                if minute == current_minute:
                    self._requests[user_id][i] = (minute, count + 1)
                    updated = True
                    break
            if not updated:
                self._requests[user_id].append((current_minute, 1))
            return True, {
                'allowed': True,
                'limit': limit_per_minute,
                'current': current_count + 1,
                'remaining': limit_per_minute - current_count - 1,
                'reset_time': (current_minute + 1) * 60
            }

    class SecurityLogger:
        @staticmethod
        def log_auth_attempt(api_key: str, ip: str, success: bool, reason: str = None):
            masked_key = SpeechAuthUtil.mask_sensitive_info(api_key, visible_chars=8)
            status_msg = "成功" if success else f"失败: {reason}"
            logger.info(f"API认证 - 密钥: {masked_key}, IP: {ip}, 状态: {status_msg}")

        @staticmethod
        def log_rate_limit_exceeded(user_id: str, ip: str, limit: int):
            logger.warning(f"速率限制超出 - 用户: {user_id}, IP: {ip}, 限制: {limit}/分钟")

        @staticmethod
        def log_permission_denied(user_id: str, resource: str, reason: str):
            logger.warning(f"权限被拒绝 - 用户: {user_id}, 资源: {resource}, 原因: {reason}")

    rate_limiter = RateLimiter()
    security_logger = SecurityLogger()

    @staticmethod
    async def verify_api_key(db: AsyncSession, api_key: str) -> Optional[SpeechClientUserDO]:
        """
        验证API密钥并返回客户端用户信息
        
        :param db: 数据库会话
        :param api_key: API密钥
        :return: 客户端用户对象或None
        """
        try:
            if not api_key:
                return None
            
            # 根据API密钥获取用户
            client_user = await ClientUserDao.get_client_user_by_api_key(db, api_key)
            
            if not client_user:
                logger.warning(f"无效的API密钥: {api_key[:8]}...")
                return None
            
            # 检查用户状态
            if client_user.status != 1:
                logger.warning(f"已禁用的用户尝试使用API: {client_user.username}")
                return None
            
            # 更新最后登录信息
            await ClientUserDao.update_last_login(db, client_user.client_user_id)
            
            return client_user
            
        except Exception as e:
            logger.error(f"验证API密钥失败: {str(e)}")
            return None

    @staticmethod
    def get_client_ip(request: Request) -> str:
        """
        获取客户端真实IP地址
        
        :param request: FastAPI请求对象
        :return: 客户端IP地址
        """
        # 尝试从各种header中获取真实IP
        forwarded_for = request.headers.get("X-Forwarded-For")
        if forwarded_for:
            # X-Forwarded-For可能包含多个IP，取第一个
            return forwarded_for.split(",")[0].strip()
        
        real_ip = request.headers.get("X-Real-IP")
        if real_ip:
            return real_ip.strip()
        
        # 从连接信息中获取IP
        if hasattr(request.client, 'host'):
            return request.client.host
        
        return "unknown"

    @staticmethod
    def generate_api_key_pair() -> tuple[str, str]:
        """
        生成API密钥对
        
        :return: (api_key, api_secret)
        """
        # 生成32位API Key
        api_key = secrets.token_urlsafe(24)  # 32字符
        
        # 生成64位API Secret
        api_secret = secrets.token_urlsafe(48)  # 64字符
        
        return api_key, api_secret

    @staticmethod
    def hash_api_secret(api_secret: str, salt: str = None) -> tuple[str, str]:
        """
        对API密钥进行哈希处理
        
        :param api_secret: API密钥
        :param salt: 盐值，如果不提供会自动生成
        :return: (hash_value, salt)
        """
        if not salt:
            salt = secrets.token_hex(16)  # 32字符的盐值
        
        # 使用SHA-256哈希
        hash_obj = hashlib.sha256((api_secret + salt).encode('utf-8'))
        hash_value = hash_obj.hexdigest()
        
        return hash_value, salt

    @staticmethod
    def verify_api_secret(api_secret: str, stored_hash: str, salt: str) -> bool:
        """
        验证API密钥
        
        :param api_secret: 待验证的API密钥
        :param stored_hash: 存储的哈希值
        :param salt: 盐值
        :return: 验证是否通过
        """
        try:
            computed_hash, _ = SpeechAuthUtil.hash_api_secret(api_secret, salt)
            return computed_hash == stored_hash
        except Exception:
            return False

    @staticmethod
    def validate_ip_whitelist(client_ip: str, whitelist: list) -> bool:
        """
        验证IP是否在白名单中
        
        :param client_ip: 客户端IP
        :param whitelist: IP白名单列表
        :return: 是否在白名单中
        """
        if not whitelist or not client_ip:
            return True  # 没有白名单限制时允许所有IP
        
        # 支持单个IP和CIDR格式
        for allowed_ip in whitelist:
            if SpeechAuthUtil._ip_in_range(client_ip, allowed_ip):
                return True
        
        return False

    @staticmethod
    def _ip_in_range(ip: str, ip_range: str) -> bool:
        """
        检查IP是否在指定范围内
        
        :param ip: 待检查的IP
        :param ip_range: IP范围（单个IP或CIDR格式）
        :return: 是否在范围内
        """
        try:
            import ipaddress
            
            # 如果范围是单个IP
            if '/' not in ip_range:
                return ip == ip_range
            
            # CIDR格式
            network = ipaddress.ip_network(ip_range, strict=False)
            return ipaddress.ip_address(ip) in network
            
        except (ValueError, ipaddress.AddressValueError):
            # 如果IP格式不正确，回退到字符串比较
            return ip == ip_range

    @staticmethod
    async def check_rate_limit(user_id: str, limit_per_minute: int) -> dict:
        """
        检查速率限制
        
        :param user_id: 用户ID
        :param limit_per_minute: 每分钟限制数
        :return: 限制信息
        """
        allowed, info = await SpeechAuthUtil.rate_limiter.is_allowed(user_id, limit_per_minute)
        
        if not allowed:
            import time
            raise HTTPException(
                status_code=status.HTTP_429_TOO_MANY_REQUESTS,
                detail="请求过于频繁，请稍后再试",
                headers={"Retry-After": str(int(info['reset_time'] - time.time()))}
            )
        
        return info

    @staticmethod
    def mask_sensitive_info(text: str, mask_char: str = "*", visible_chars: int = 4) -> str:
        """
        屏蔽敏感信息
        
        :param text: 原始文本
        :param mask_char: 掩码字符
        :param visible_chars: 可见字符数量
        :return: 掩码后的文本
        """
        if not text or len(text) <= visible_chars:
            return mask_char * len(text) if text else ""
        
        return text[:visible_chars] + mask_char * (len(text) - visible_chars)

    @staticmethod
    def validate_model_permission(user_models: list, requested_model: str) -> bool:
        """
        验证模型权限
        
        :param user_models: 用户允许的模型列表
        :param requested_model: 请求的模型
        :return: 是否有权限
        """
        return requested_model in user_models

    @staticmethod
    def validate_feature_permission(user_features: dict, requested_feature: str) -> bool:
        """
        验证功能权限
        
        :param user_features: 用户功能权限字典
        :param requested_feature: 请求的功能
        :return: 是否有权限
        """
        return user_features.get(requested_feature, False) 